// 单例模式
#include <iostream>

// 懒汉式，多线程
class CSingleton {
  public:
    static CSingleton *GetInstance() {
      if (m_pInstance == nullptr) {
        lock();
        if (m_pInstance == nullptr) {
          m_pInstance = new CSingleton();
        }
        unlock();
      }
      return m_pInstance;
    }
  protected:
    CSingleton() {};
  private:
    static CSingleton *m_pInstance;
    static void lock() {
      std::cout << "lock..." << std::endl;
    }
    static void unlock() {
      std::cout << "unlock..." << std::endl;
    }
};
CSingleton* CSingleton::m_pInstance = nullptr;

// 饿汉式
class CSingleton1 {
  public:
    static CSingleton1 *GetInstance() {
      static CSingleton1 m_pInstance;
      return &m_pInstance;
    }
  private:
    CSingleton1() {};
};

// 有派生类时
class base {
  public:
    static base* GetInstance(std::string name);
    virtual void show() {
      std::cout << "show base" << std::endl;
    }
  protected:
    base() {};
  private:
    static base* instance;
};
base* base::instance = nullptr;

class derived1: public base {
  friend class base;
  public:
    void show () {
      std::cout << "show derived1" << std::endl;
    }
  private:
    derived1() {};
};

class derived2: public base {
  friend class base;
  public:
    void show () {
      std::cout << "show derived2" << std::endl;
    }
  private:
    derived2() {};
};

base* base::GetInstance(std::string name) {
  if (instance == nullptr) {
    if (name == "derived1") {
      instance = new derived1();
    } else if (name == "derived2") {
      instance = new derived2();
    } else {
      instance = new base();
    }
  }
  return instance;
}

int main() {
  CSingleton* singleton1 = CSingleton::GetInstance();
  CSingleton* singleton2 = CSingleton::GetInstance();
  std::cout << "should be same singleton: " << (singleton1 == singleton2) << std::endl;

  CSingleton1* singleton3 = CSingleton1::GetInstance();
  CSingleton1* singleton4 = CSingleton1::GetInstance();
  std::cout << "should be same singleton1: " << (singleton3 == singleton4) << std::endl;

  // only generate a GetInstance
  base* base_instance = base::GetInstance("base");
  base_instance->show();

  base* derived1_instance = base::GetInstance("derived1");
  derived1_instance->show();

  base* derived2_instance = base::GetInstance("derived2");
  derived2_instance->show();

  return 0;
}
